fix(iam,organizations,core): gate cross-account AssumeRoot on org membership (bug-hunt 5.2)#2292
Merged
Conversation
…bership (bug-hunt 5.2) `sts:AssumeRoot` into another account was gated only by the caller account's own `organizations_root_sessions` flag, so any account that enabled RootSessions could mint `:root` credentials for ANY account — in or out of its organization — with no management-account or membership check. Cross-account AssumeRoot now additionally requires that the organization topology authorize it: the target must be a member of the caller's organization AND the caller must be that org's management account (or a registered delegated administrator for centralized root access). Same-account AssumeRoot is unchanged (always allowed, per the recorded conformance baseline). - core: new `OrgMembershipResolver` trait (`can_assume_root_into`). - organizations: `OrganizationsMembershipResolver` implements it over the shared org state (management-account / delegated-admin + member-enrollment checks). - iam: `StsService::with_org_membership`; the cross-account branch consults the resolver. With no resolver wired (single-account setups), cross-account AssumeRoot is denied — there is no org topology to authorize it. - server: wire the resolver from the live organizations state. Tests: organizations resolver (management/member/non-member/non-management/ delegated-admin/no-org); STS assume_root (cross-account allowed via a mock resolver, denied when the org disallows, denied with no resolver). Conformance `sts_assume_root` is same-account and unaffected.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
sts:AssumeRootinto another account was gated only by the caller account's ownorganizations_root_sessionsflag. Any account that enabled RootSessions could therefore mint:rootcredentials for any account — inside or outside its organization — with no management-account or membership check. (bug-hunt 5.2, MED cross-account escalation.)Cross-account AssumeRoot now additionally requires the organization topology to authorize it:
Same-account AssumeRoot is unchanged (always allowed — the recorded conformance baseline
sts_assume_roottargets the caller's own account).Design
auth.rs): newOrgMembershipResolvertrait —can_assume_root_into(caller, target). Mirrors the existingScpResolverboundary so IAM/STS need no direct dependency on the organizations crate.resolver.rs):OrganizationsMembershipResolverimplements it over the shared org state — target must be enrolled, caller must be management or a delegated admin foriam.amazonaws.com.StsService): newwith_org_membership(...)builder; the cross-account branch consults the resolver. With no resolver wired (single-account setups / unit tests), cross-account AssumeRoot is denied — there is no org topology to authorize it.main.rs): wires the resolver from the live organizations state.Test plan
cargo test -p fakecloud-organizations --lib membership_resolver— management→member allowed; non-member target, non-management caller, and no-org all denied; delegated admin allowed.cargo test -p fakecloud-iam --lib assume_root— cross-account allowed via a mock resolver; denied when the org disallows; denied with no resolver; same-account still allowed.cargo build --workspace+cargo build --bin fakecloudclean (main.rs wiring).cargo clippy -p fakecloud-core -p fakecloud-organizations -p fakecloud-iam --tests -- -D warningsclean.No API surface / SDK / docs change (authorization behavior only; the operation shape is unchanged).
Summary by cubic
Fixes a cross-account escalation in
sts:AssumeRoot. Cross-account AssumeRoot now requires the target to be in the caller’s org and the caller to be the management account or a delegated admin; same-account is unchanged.Bug Fixes
OrgMembershipResolverinfakecloud-core; implementedOrganizationsMembershipResolverinfakecloud-organizations.StsServiceto consult the resolver and deny cross-account AssumeRoot when not authorized or when no resolver is wired; added focused tests.fakecloud-server.Migration
StsServiceoutside our server, callwith_org_membership(...)to enable authorized cross-account AssumeRoot; without it, cross-account is denied.Written for commit 14e6e38. Summary will update on new commits.